from flask import Flask,request,jsonify

import time
import threading
import modbus_tk
import json
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
from flask_cors import *
import serial
import serial.tools.list_ports
import os
import binascii
import re


def modbusInit(config):
    try:
        master = modbus_rtu.RtuMaster(serial.Serial(port=config["portModel"],baudrate=config["rateModel"], bytesize=config["byteModel"], parity=config["checkModel"], stopbits=config["stopModel"]))
        master.set_timeout(0.1)
        master.set_verbose(True)
        return master
    except Exception as exc:
        print(str(exc))
        alarm = (str(exc))
    return alarm


app = Flask(__name__)
CORS(app, supports_credentials=True)

@app.route('/status')
def status():
    global master
    return jsonify({"msg":"success","data":{'status':master != None},"code":200})

@app.route('/duankai')
def duankai():
    global master
    try:
        master.close()
        master = None
        return jsonify({"msg":"success","code":200})
    except:
        return jsonify({"msg":"未连接","code":400})

#设备写入配置
@app.route('/download_config',methods=["POST"])
def downloadConfig():
    eid = int(request.json.get("eid"))
    paramArr = request.json.get("paramArr")
    keyArr = request.json.get("keyArr")

    key1_param = keyArr[0]["key_param"]
    key1_name = afterInsertZero(str_to_list(keyArr[0]["key_name"]))
    # print("key1_name")
    # print(key1_name)
    # print("key1_name")
    key1_relay = keyArr[0]["key_relay"]
    key1_led = keyArr[0]["key_led"]

    key2_param = keyArr[1]["key_param"]
    key2_name = afterInsertZero(str_to_list(keyArr[1]["key_name"]))
    key2_relay = keyArr[1]["key_relay"]
    key2_led = keyArr[1]["key_led"]
    
    key3_param = keyArr[2]["key_param"]
    key3_name = afterInsertZero(str_to_list(keyArr[2]["key_name"]))
    key3_relay = keyArr[2]["key_relay"]
    key3_led = keyArr[2]["key_led"]
    
    key4_param = keyArr[3]["key_param"]
    key4_name = afterInsertZero(str_to_list(keyArr[3]["key_name"]))
    key4_relay = keyArr[3]["key_relay"]
    key4_led = keyArr[3]["key_led"]
    
    key5_param = keyArr[4]["key_param"]
    key5_name = afterInsertZero(str_to_list(keyArr[4]["key_name"]))
    key5_relay = keyArr[4]["key_relay"]
    key5_led = keyArr[4]["key_led"]
    
    key6_param = keyArr[5]["key_param"]
    key6_name = afterInsertZero(str_to_list(keyArr[5]["key_name"]))
    key6_relay = keyArr[5]["key_relay"]
    key6_led = keyArr[5]["key_led"]
    
    key7_param = keyArr[6]["key_param"]
    key7_name = afterInsertZero(str_to_list(keyArr[6]["key_name"]))
    key7_relay = keyArr[6]["key_relay"]
    key7_led = keyArr[6]["key_led"]
    
    key8_param = keyArr[7]["key_param"]
    key8_name = afterInsertZero(str_to_list(keyArr[7]["key_name"]))
    key8_relay = keyArr[7]["key_relay"]
    key8_led = keyArr[7]["key_led"]
    master.set_timeout(0.2)

    #删除按键次数记录
    del key1_param[5]
    del key2_param[5]
    del key3_param[5]
    del key4_param[5]
    del key5_param[5]
    del key6_param[5]
    del key7_param[5]
    del key8_param[5]

    try:
        result1 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,42,output_value=paramArr)

        result2 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,60,output_value=key1_param)
        result_name1 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,66,output_value=key1_name)
        result3 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,75,output_value=key1_relay)
        result4 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,95,output_value=key1_led)

        result5 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,135,output_value=key2_param)
        result_name2 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,141,output_value=key2_name)
        result6 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,150,output_value=key2_relay)
        result7 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,170,output_value=key2_led)
        
        result8 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,210,output_value=key3_param)
        result_name3 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,216,output_value=key3_name)
        result9 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,225,output_value=key3_relay)
        result10 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,245,output_value=key3_led)
        
        result11 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,285,output_value=key4_param)
        result_name4 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,291,output_value=key4_name)
        result12 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,300,output_value=key4_relay)
        result13 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,320,output_value=key4_led)
        
        result14 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,360,output_value=key5_param)
        result_name5 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,366,output_value=key5_name)
        result15 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,375,output_value=key5_relay)
        result16 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,395,output_value=key5_led)
        
        result17 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,435,output_value=key6_param)
        result_name6 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,441,output_value=key6_name)
        result18 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,450,output_value=key6_relay)
        result19 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,470,output_value=key6_led)
        
        result20 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,510,output_value=key7_param)
        result_name7 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,516,output_value=key7_name)
        result21 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,525,output_value=key7_relay)
        result22 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,545,output_value=key7_led)
        
        result23 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,585,output_value=key8_param)
        result_name8 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,591,output_value=key8_name)
        result24 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,600,output_value=key8_relay)
        result25 = master.execute( eid ,cst.WRITE_MULTIPLE_REGISTERS,620,output_value=key8_led)

        result26 = master.execute( eid ,cst.WRITE_SINGLE_REGISTER,42,output_value=21930)
        result27= master.execute( eid ,cst.WRITE_SINGLE_REGISTER,42,output_value=0)

        return jsonify({"msg":"success","code":200})
    except Exception as e:
        return jsonify({"msg":str(e),"code":400})

#获取设备配置
@app.route('/equipconfig')
def equipconfig():
    eid = int(request.args.get("eid"))
    try:
        paramArr   = master.execute( eid , cst.READ_HOLDING_REGISTERS, 42, 8) #配置参数

        key1_param = master.execute( eid , cst.READ_HOLDING_REGISTERS, 60, 6) #按键1参数
        key1_name = master.execute( eid , cst.READ_HOLDING_REGISTERS, 66, 9) #按键1名称
        
        key1_relay = master.execute( eid , cst.READ_HOLDING_REGISTERS, 75, 20) #按键1继电器
        key1_led  = master.execute( eid , cst.READ_HOLDING_REGISTERS, 95, 40) #按键1LED1~4

        key2_param = master.execute( eid , cst.READ_HOLDING_REGISTERS, 135, 6) #按键2参数
        key2_name = master.execute( eid , cst.READ_HOLDING_REGISTERS, 141, 9) #按键2名称
        key2_relay = master.execute( eid , cst.READ_HOLDING_REGISTERS, 150,20) #按键2继电器
        key2_led  = master.execute( eid , cst.READ_HOLDING_REGISTERS, 170,40) #按键2LED1~4

        key3_param = master.execute( eid , cst.READ_HOLDING_REGISTERS, 210,6) #按键3参数
        key3_name = master.execute( eid , cst.READ_HOLDING_REGISTERS, 216, 9) #按键3名称
        key3_relay = master.execute( eid , cst.READ_HOLDING_REGISTERS, 225,20) #按键3继电器
        key3_led  = master.execute( eid , cst.READ_HOLDING_REGISTERS, 245,40) #按键3LED1~4

        key4_param = master.execute( eid , cst.READ_HOLDING_REGISTERS, 285, 6) #按键4参数
        key4_name = master.execute( eid , cst.READ_HOLDING_REGISTERS, 291, 9) #按键4名称
        key4_relay = master.execute( eid , cst.READ_HOLDING_REGISTERS, 300, 20) #按键4继电器
        key4_led  = master.execute( eid , cst.READ_HOLDING_REGISTERS, 320, 40) #按键4LED1~4
 
        key5_param = master.execute( eid , cst.READ_HOLDING_REGISTERS, 360, 6) #按键5参数
        key5_name = master.execute( eid , cst.READ_HOLDING_REGISTERS, 366, 9) #按键5名称
        key5_relay = master.execute( eid , cst.READ_HOLDING_REGISTERS, 375, 20) #按键5继电器
        key5_led  = master.execute( eid , cst.READ_HOLDING_REGISTERS, 395, 40) #按键5LED1~4
 
        key6_param = master.execute( eid , cst.READ_HOLDING_REGISTERS, 435, 6) #按键6参数
        key6_name = master.execute( eid , cst.READ_HOLDING_REGISTERS, 441, 9) #按键6名称
        key6_relay = master.execute( eid , cst.READ_HOLDING_REGISTERS, 450, 20) #按键6继电器
        key6_led  = master.execute( eid , cst.READ_HOLDING_REGISTERS, 470, 40) #按键6LED1~4

        key7_param = master.execute( eid , cst.READ_HOLDING_REGISTERS, 510, 6) #按键7参数
        key7_name = master.execute( eid , cst.READ_HOLDING_REGISTERS, 516, 9) #按键7名称
        key7_relay = master.execute( eid , cst.READ_HOLDING_REGISTERS, 525, 20) #按键7继电器
        key7_led  = master.execute( eid , cst.READ_HOLDING_REGISTERS, 545, 40) #按键7LED1~4

        key8_param = master.execute( eid , cst.READ_HOLDING_REGISTERS, 585, 6) #按键8参数
        key8_name = master.execute( eid , cst.READ_HOLDING_REGISTERS, 591, 9) #按键8名称
        key8_relay = master.execute( eid , cst.READ_HOLDING_REGISTERS, 600, 20) #按键8继电器
        key8_led  = master.execute( eid , cst.READ_HOLDING_REGISTERS, 620, 40) #按键8LED1~4

        key1 = {
            'key_param':key1_param,
            'key_name':try_list2Str(key1_name),
            'key_relay':key1_relay,
            'key_led':key1_led
        }
        # print(key1_name)
        # print(try_list2Str(key1_name))
        key2 = {
            'key_param':key2_param,
            'key_name':try_list2Str(key2_name),
            'key_relay':key2_relay,
            'key_led':key2_led
        }
        key3 = {
            'key_param':key3_param,
            'key_name':try_list2Str(key3_name),
            'key_relay':key3_relay,
            'key_led':key3_led
        }
        key4 = {
            'key_param':key4_param,
            'key_name':try_list2Str(key4_name),
            'key_relay':key4_relay,
            'key_led':key4_led
        }
        key5 = {
            'key_param':key5_param,
            'key_name':try_list2Str(key5_name),
            'key_relay':key5_relay,
            'key_led':key5_led
        }
        key6 = {
            'key_param':key6_param,
            'key_name':try_list2Str(key6_name),
            'key_relay':key6_relay,
            'key_led':key6_led
        }
        key7 = {
            'key_param':key7_param,
            'key_name':try_list2Str(key7_name),
            'key_relay':key7_relay,
            'key_led':key7_led
        }
        key8 = {
            'key_param':key8_param,
            'key_name':try_list2Str(key8_name),
            'key_relay':key8_relay,
            'key_led':key8_led
        }
        keyArr = [key1,key2,key3,key4,key5,key6,key7,key8]

        data = {
            'paramArr':paramArr,
            'keyArr':keyArr
        }
        
        return jsonify({"msg":"success","data":data,"code":200})
    except Exception as e:
        return jsonify({"msg":str(e),"code":400})
#生成长度为length的全0数组
def newZeroArr(length):
    arr = []
    for i in range(length):
        arr.append(0)
    return arr
# 数组不足9位末位补0
def afterInsertZero(intArr):
    arrLength = len(intArr)
    if arrLength<9:
        return intArr+newZeroArr(9-arrLength)
    else:
        return intArr[0:9]
#utf8中文转16进制字符串
def str_to_hexStr(string):
    temp = binascii.hexlify(string.encode('utf-8')).decode('utf-8')
    if len(temp)%4 == 2:
        return temp + "00"
    else:
        return temp
#中文转16进制字符串再转int数组
def str_to_list(string):
    if string == '':
        return [0,0,0,0,0,0,0,0,0]
    hexStr = str_to_hexStr(string)
    # 获取十六进制编码数组  4个字符隔开   abcdefgh  =>  ['abcd','efgh']
    arr = re.sub(r"(?<=\w)(?=(?:\w\w\w\w)+$)", " ", hexStr).split(" ")
    # print(arr)
    newArr = []
    for i in arr:
        newArr.append(int(i, 16))
    return newArr
#16进制转为中文
def hexStr_to_str(hex_str):
    if hex_str[-2:] == "00":
        hex_str = hex_str[:-2]
    hexs = hex_str.encode('utf-8')
    str_bin = binascii.unhexlify(hexs)
    return str_bin.decode('utf-8')
def try_list2Str(intArr):
    try:
        return list_to_str(intArr)
    except:
        return ''
#int数组转中文  
def list_to_str(result):
    # print(result)
    tempStr = ""
    cnHexStr = ""
    for t in result:
        if t!=0:
            #数字转为16进制
            temp = str(hex(t)).replace("0x","")
            # print(cnHexStr)
            cnHexStr += temp
    #16进制转为中文
    tempStr += hexStr_to_str(cnHexStr)
    return tempStr
#通过sn设置设备id
@app.route('/equipsnsetid',methods=["POST"])
def equipsnsetid():
    try:
        serial_number = request.json.get('serial_number')
        eid = request.json.get('eid')
        result1 = master.execute( 255 , cst.WRITE_MULTIPLE_REGISTERS, 0,output_value = serial_number) #下发对应的SN号
        result2 = master.execute( 255 ,cst.WRITE_SINGLE_REGISTER,21,output_value = eid) #设置ID号
        return jsonify({"msg":"success","data":result,"code":200})
    except Exception as e:
        if str(e) == 'Response length is invalid 0':
            return jsonify({"msg":"success","code":200})
        return jsonify({"msg":str(e),"code":400})

#让所有设备退出配置ID模式
@app.route('/equipquitsn',methods=["POST"])
def equipquitsn():
    try:
        result = master.execute( 255 ,cst.WRITE_SINGLE_REGISTER,20,output_value = 0) #让设备退出分配ID模式
        return jsonify({"msg":"success","data":result,"code":200})
    except Exception as e:
        if str(e) == 'Response length is invalid 0':
            return jsonify({"msg":"success","code":200})
        return jsonify({"msg":str(e),"code":400})

#让所有设备进入配置ID模式
@app.route('/equipinitpre',methods=["POST"])
def equipinitpre():
    global master
    try:
        master.close()
    except:
        print("master为空")
    try:
        master = modbusInit(request.json)
        result = master.execute( 255 ,cst.WRITE_SINGLE_REGISTER,20,output_value = 1) #让设备进入分配ID模式
        return jsonify({"msg":"success","data":result,"code":200})
    except Exception as e:
        if str(e) == 'Response length is invalid 0':
            return jsonify({"msg":"success","code":200})
        return jsonify({"msg":str(e),"code":400})

#轮训接口   查询sn
@app.route('/equipwhilesn',methods=["POST"])
def equipwhilesn():
    try:
        result = master.execute( 255 , cst.READ_INPUT_REGISTERS, 0,10) #查询SN号
        return jsonify({"msg":"success","data":result,"code":200})
    except Exception as e:
        if str(e) == 'Response length is invalid 0':
            return jsonify({"msg":"请按开关按钮","code":400})
        return jsonify({"msg":str(e),"code":400})

#获取设备列表
@app.route('/equipinit',methods=["POST"])
def equipinit():
    global master
    try:
        master.close()
    except:
        print("master为空")
    try:
        master = modbusInit(request.json)
        start = request.json["start"]
        end = request.json["end"]
        result = ""
        arr =[]
        for i in range(start,end):
            equipDict = {}
            try:
                result = master.execute(i, cst.READ_INPUT_REGISTERS, 0, 20)
                serial_num  = master.execute( i , cst.READ_INPUT_REGISTERS, 30, 10) #SN号
                equipDict["label"] = list_to_str(result)
                equipDict["value"] = i
                equipDict["id"] = i
                equipDict["sn"] = serial_num
                arr.append(equipDict)
            except Exception as e:
                print(str(i)+":"+str(e))
        return jsonify({"msg":"success","data":arr,"code":200})
    except Exception as e:
        return jsonify({"msg":str(e),"code":400})

#获取端口列表
@app.route('/portlist')
def portlist():
    try:
        port_list = list(serial.tools.list_ports.comports())
        portList = []
        for each_port in port_list:
            portDict = {}
            portDict["value"] = each_port[0]
            portDict["label"] = each_port[1]
            portList.append(portDict)
        return jsonify({"msg":"success","data":portList,"code":200})
    except Exception as e:
        return jsonify({"msg":str(e),"code":400})

#退出接口
@app.route('/clear')
def clear():
    try:
        master.close()
        return jsonify({"msg":"success","code":200})
    except Exception as e:
        return jsonify({"msg":str(e),"code":400})
    
#杀死程序
def kill_port(port):
    find_port= 'netstat -ano | findstr %s' % port
    result = os.popen(find_port)
    text = result.read()
    pids = re.findall('LISTENING       (\d+)\\n',text)
    for pid in pids:
        find_kill= 'taskkill -f -pid %s' %pid
        os.popen(find_kill)

if __name__ == '__main__':
    global master
    master = None
    try:
        kill_port(7778)
    except Exception as e:
        print(e)
    app.run(port=7778)